package com.newly.common.base.entity.auth;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.newly.common.base.constants.AuthConstant;
import com.newly.common.base.exception.AuthException;
import lombok.Data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @program: newly-parent
 * @remark: 当前用户详情信息
 * @author: guan
 * @create: 2021-12-23 05:18
 */
@Data
public class CurrentTenantDetails extends AbstractCurrentTenant implements ICurrentTenant {

    public CurrentTenantDetails(TenantDetails tenantDetails) {
        this.tenantDetails = tenantDetails;
    }

    @Override
    public List<AuthPayload.AuthEntity> getEntities(AuthConstant.AuthEntityType entityType) {
        List<AuthPayload> authPayloads = getAuthPayloads();
        if (ObjectUtil.isEmpty(authPayloads)) return null;

        for (AuthPayload authPayload : authPayloads) {
            Map<AuthConstant.AuthEntityType, List<AuthPayload.AuthEntity>>
                    authEntities = authPayload.getAuthEntities();
            return authEntities.get(entityType);
        }
        return null;
    }

    @Override
    public List<AuthPayload.AuthEntity> getEntities(Integer roleId, AuthConstant.AuthEntityType entityType) {
        List<AuthPayload> authPayloads = getAuthPayloads();
        if (ObjectUtil.isEmpty(authPayloads)) return null;

        for (AuthPayload authPayload : authPayloads) {
            if (!ObjectUtil.isEmpty(roleId)) {
                if (!roleId.equals(authPayload.getRoleId())) {
                    continue;
                }
            }
            Map<AuthConstant.AuthEntityType, List<AuthPayload.AuthEntity>>
                    authEntities = authPayload.getAuthEntities();
            return authEntities.get(entityType);
        }
        return null;
    }

    @Override
    public List<String> getEntityIds(AuthConstant.AuthEntityType entityType) {
        List<AuthPayload.AuthEntity> entities = this.getEntities(entityType);
        if (!ObjectUtil.isEmpty(entities)) {
            return entities.stream().map(entity -> entity.getEntityId())
                    .distinct().collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public List<String> getEntityIds(Integer roleId, AuthConstant.AuthEntityType entityType) {
        List<AuthPayload.AuthEntity> entities = this.getEntities(roleId, entityType);
        if (!ObjectUtil.isEmpty(entities)) {
            return entities.stream().map(entity -> entity.getEntityId())
                    .distinct().collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public List<String> getEntityIds() {
        return getEntityIds(null);
    }

    @Override
    public List<Integer> getMenuIds() {
        List<String> entityIds = getEntityIds(AuthConstant.AuthEntityType.MENU);
        if (ObjectUtil.isNotEmpty(entityIds)) {
            return entityIds.stream().map(entityId -> Integer.parseInt(entityId))
                    .distinct().collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public List<Integer> getRoleIds() {
        List<AuthPayload> authPayloads = getAuthPayloads();
        if (!ObjectUtil.isEmpty(authPayloads))
            return authPayloads.stream().map(authPayload -> authPayload.getRoleId())
                    .collect(Collectors.toList());
        return null;
    }

    @Override
    public List<Integer> getSelfRoleIds() {
        List<AuthPayload> authPayloads = getAuthPayloads();
        if (!ObjectUtil.isEmpty(authPayloads)) {
            return authPayloads.stream()
                    .filter(authPayload -> authPayload.isCurrentFlag())
                    .map(authPayload -> authPayload.getRoleId())
                    .collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public Integer getSelfRoleId() {
        List<Integer> roleIds = getSelfRoleIds();
        if (!ObjectUtil.isEmpty(roleIds)) {
            return roleIds.get(0);
        }
        return null;
    }

    @Override
    public boolean isDev() {
        return this.getType() == AuthConstant.UserType.DEV.getCode();
    }

    @Override
    public boolean hasMenuIds(List<Integer> menuIds) {
        if (ObjectUtil.isEmpty(menuIds)) return true;

        List<Integer> allMenuIds = this.getMenuIds();
        if (ObjectUtil.isEmpty(allMenuIds)) return false;

        List<Integer> tmpMenuIds = new ArrayList<>(menuIds.size());
        for (Integer menuId : menuIds) {
            tmpMenuIds.add(menuId);
        }
        // 取差值之后如果长度为0后说明具备所有菜单
        tmpMenuIds.removeAll(allMenuIds);
        return tmpMenuIds.size() <= 0;
    }

    @Override
    public boolean hasMenuIds(Integer... menuIds) {
        return hasMenuIds(Arrays.asList(menuIds));
    }

    @Override
    public boolean hasMenuId(Integer menuId) {
        return hasMenuIds(menuId);
    }

    @Override
    public boolean hasRoles(List<Integer> roleIds) {
        if (ObjectUtil.isEmpty(roleIds)) return true;

        List<Integer> allRole = this.getRoleIds();
        if (ObjectUtil.isEmpty(allRole)) return false;

        List<Integer> tmpRoleIds = new ArrayList<>(roleIds.size());
        for (Integer roleId : roleIds) {
            tmpRoleIds.add(roleId);
        }
        tmpRoleIds.removeAll(allRole);
        return tmpRoleIds.size() <= 0;
    }

    @Override
    public boolean hasRoles(Integer... roleIds) {
        return hasRoles(Arrays.asList(roleIds));
    }

    @Override
    public boolean hasRole(Integer roleId) {
        return hasRoles(roleId);
    }

    @Override
    public boolean hasSelfRoles(List<Integer> roleIds) {
        if (ObjectUtil.isEmpty(roleIds)) return true;

        List<Integer> allSelfRoleIds = this.getSelfRoleIds();
        if (ObjectUtil.isEmpty(allSelfRoleIds)) return false;

        List<Integer> tmpRoleIds = roleIds.stream().collect(Collectors.toList());
        tmpRoleIds.removeAll(allSelfRoleIds);
        return tmpRoleIds.size() <= 0;
    }

    @Override
    public boolean hasSelfRoles(Integer... roleIds) {
        return hasSelfRoles(Arrays.asList(roleIds));
    }

    @Override
    public boolean hasSelfRole(Integer roleId) {
        return hasSelfRoles(Arrays.asList(roleId));
    }

    @Override
    public boolean hasEntities(AuthConstant.AuthEntityType entity, List<String> entityIds) {
        if (ObjectUtil.isEmpty(entityIds)) return true;

        List<String> allEntityIds = this.getEntityIds(entity);
        if (ObjectUtil.isEmpty(allEntityIds)) return false;

        List<String> tmpEntityIds = entityIds.stream().collect(Collectors.toList());
        tmpEntityIds.removeAll(allEntityIds);
        return tmpEntityIds.size() <= 0;
    }

    @Override
    public boolean hasEntity(AuthConstant.AuthEntityType entity, String entityId) {
        return hasEntities(entity, Arrays.asList(entityId));
    }

    @Override
    public ICurrentTenant assertDev(int orientation, String _errMsg) {
        String errMsg = this.getErrMsg(_errMsg);
        try {
            if (INCLUDE == orientation) {
                Assert.isTrue(isDev(), errMsg);
            } else if (EXCLUDE == orientation) {
                Assert.isFalse(isDev(), errMsg);
            }
        } catch (IllegalArgumentException e) {
            throw new AuthException(errMsg);
        }
        return this;
    }

    @Override
    public ICurrentTenant assertIsDev(String errMsg) {
        return assertDev(INCLUDE, errMsg);
    }

    @Override
    public ICurrentTenant assertIsDev() {
        return assertIsDev(null);
    }

    @Override
    public ICurrentTenant assertNoDev(String errMsg) {
        return assertDev(EXCLUDE, errMsg);
    }

    @Override
    public ICurrentTenant assertNoDev() {
        return assertNoDev(null);
    }

    @Override
    public ICurrentTenant assertMenus(int orientation, List<Integer> menuIds, String _errMsg) {
        String errMsg = this.getErrMsg(_errMsg);
        try {
            if (INCLUDE == orientation) {
                Assert.isTrue(hasMenuIds(menuIds), errMsg);
            } else if (EXCLUDE == orientation) {
                Assert.isFalse(hasMenuIds(menuIds), errMsg);
            }
        } catch (Exception e) {
            throw new AuthException(e.getMessage());
        }
        return this;
    }

    @Override
    public ICurrentTenant assertIncludeMenus(List<Integer> menuIds, String errMsg) {
        return assertMenus(INCLUDE, menuIds, errMsg);
    }

    @Override
    public ICurrentTenant assertIncludeMenus(List<Integer> menuIds) {
        return assertIncludeMenus(menuIds, null);
    }

    @Override
    public ICurrentTenant assertIncludeMenu(Integer menuId, String errMsg) {
        return assertIncludeMenus(Arrays.asList(menuId), errMsg);
    }

    @Override
    public ICurrentTenant assertIncludeMenu(Integer menuId) {
        return assertIncludeMenu(menuId, null);
    }

    @Override
    public ICurrentTenant assertExcludeMenus(List<Integer> menuIds, String errMsg) {
        return assertMenus(EXCLUDE, menuIds, errMsg);
    }

    @Override
    public ICurrentTenant assertExcludeMenus(List<Integer> menuIds) {
        return assertExcludeMenus(menuIds, null);
    }

    @Override
    public ICurrentTenant assertExcludeMenu(Integer menuId, String errMsg) {
        return assertExcludeMenus(Arrays.asList(menuId), errMsg);
    }

    @Override
    public ICurrentTenant assertExcludeMenu(Integer menuId) {
        return assertExcludeMenu(menuId, null);
    }

    @Override
    public ICurrentTenant assertRoles(int orientation, List<Integer> roleIds, String _errMsg) throws AuthException {
        String errMsg = this.getErrMsg(_errMsg);
        try {
            if (INCLUDE == orientation) {
                Assert.isTrue(hasRoles(roleIds), errMsg);
            } else if (EXCLUDE == orientation) {
                Assert.isFalse(hasRoles(roleIds), errMsg);
            }
        } catch (IllegalArgumentException e) {
            throw new AuthException(e.getMessage());
        }
        return this;
    }

    @Override
    public ICurrentTenant assertIncludeRoles(List<Integer> roleIds, String errMsg) throws AuthException {
        return assertRoles(INCLUDE, roleIds, errMsg);
    }

    @Override
    public ICurrentTenant assertIncludeRoles(List<Integer> roleIds) throws AuthException {
        return assertIncludeRoles(roleIds, null);
    }

    @Override
    public ICurrentTenant assertIncludeRole(Integer roleId, String errMsg) throws AuthException {
        return assertIncludeRoles(Arrays.asList(roleId), errMsg);
    }

    @Override
    public ICurrentTenant assertIncludeRole(Integer roleId) throws AuthException {
        return assertIncludeRole(roleId, null);
    }

    @Override
    public ICurrentTenant assertExcludeRoles(List<Integer> roleIds, String errMsg) throws AuthException {
        return assertRoles(EXCLUDE, roleIds, errMsg);
    }

    @Override
    public ICurrentTenant assertExcludeRoles(List<Integer> roleIds) throws AuthException {
        return assertExcludeRoles(roleIds, null);
    }

    @Override
    public ICurrentTenant assertExcludeRole(Integer roleId, String errMsg) throws AuthException {
        return assertExcludeRoles(Arrays.asList(roleId), errMsg);
    }

    @Override
    public ICurrentTenant assertExcludeRole(Integer roleId) throws AuthException {
        return assertExcludeRole(roleId, null);
    }

    @Override
    public ICurrentTenant assertSelfRoles(int orientation, List<Integer> roleIds, String _errMsg) throws AuthException {
        String errMsg = this.getErrMsg(_errMsg);
        try {
            if (orientation == INCLUDE) {
                Assert.isTrue(hasSelfRoles(roleIds), errMsg);
            } else if (orientation == EXCLUDE) {
                Assert.isFalse(hasSelfRoles(roleIds), errMsg);
            }
        } catch (IllegalArgumentException e) {
            throw new AuthException(e.getMessage());
        }
        return this;
    }

    @Override
    public ICurrentTenant assertIncludeSelfRoles(List<Integer> roleIds, String errMsg) throws AuthException {
        return assertSelfRoles(INCLUDE, roleIds, errMsg);
    }

    @Override
    public ICurrentTenant assertIncludeSelfRoles(List<Integer> roleIds) throws AuthException {
        return assertIncludeSelfRoles(roleIds, null);
    }

    @Override
    public ICurrentTenant assertIncludeSelfRole(Integer roleId, String errMsg) throws AuthException {
        return assertIncludeSelfRoles(Arrays.asList(roleId), errMsg);
    }

    @Override
    public ICurrentTenant assertIncludeSelfRole(Integer roleId) throws AuthException {
        return assertIncludeSelfRole(roleId, null);
    }

    @Override
    public ICurrentTenant assertExcludeSelfRoles(List<Integer> roleIds, String errMsg) throws AuthException {
        return assertSelfRoles(EXCLUDE, roleIds, errMsg);
    }

    @Override
    public ICurrentTenant assertExcludeSelfRoles(List<Integer> roleIds) throws AuthException {
        return assertExcludeSelfRoles(roleIds, null);
    }

    @Override
    public ICurrentTenant assertExcludeSelfRole(Integer roleId, String errMsg) throws AuthException {
        return assertExcludeSelfRoles(Arrays.asList(roleId), errMsg);
    }

    @Override
    public ICurrentTenant assertExcludeSelfRole(Integer roleId) throws AuthException {
        return assertExcludeSelfRole(roleId, null);
    }

    @Override
    public ICurrentTenant assertEntities(int orientation, AuthConstant.AuthEntityType authEntityType,
                                         List<String> entityIds, String _errMsg) throws AuthException {
        String errMsg = this.getErrMsg(_errMsg);
        try {
            if (orientation == INCLUDE) {
                Assert.isTrue(hasEntities(authEntityType, entityIds), errMsg);
            } else if (orientation == EXCLUDE) {
                Assert.isFalse(hasEntities(authEntityType, entityIds), errMsg);
            }
        } catch (IllegalArgumentException e) {
            throw new AuthException(e.getMessage());
        }
        return null;
    }

    @Override
    public ICurrentTenant assertIncludeEntities(AuthConstant.AuthEntityType authEntityType,
                                                List<String> entityIds, String errMsg) throws AuthException {
        return assertEntities(INCLUDE, authEntityType, entityIds, errMsg);
    }

    @Override
    public ICurrentTenant assertIncludeEntities(AuthConstant.AuthEntityType authEntityType,
                                                List<String> entityIds) throws AuthException {
        return assertIncludeEntities(authEntityType, entityIds, null);
    }

    @Override
    public ICurrentTenant assertIncludeEntity(AuthConstant.AuthEntityType authEntityType, String entityId, String errMsg) throws AuthException {
        return assertIncludeEntities(authEntityType, Arrays.asList(entityId), errMsg);
    }

    @Override
    public ICurrentTenant assertIncludeEntity(AuthConstant.AuthEntityType authEntityType, String entityId) throws AuthException {
        return assertIncludeEntity(authEntityType, entityId, null);
    }

    @Override
    public ICurrentTenant assertExcludeEntities(AuthConstant.AuthEntityType authEntityType, List<String> entityIds,
                                                String errMsg) throws AuthException {
        return assertEntities(EXCLUDE, authEntityType, entityIds, errMsg);
    }

    @Override
    public ICurrentTenant assertExcludeEntities(AuthConstant.AuthEntityType authEntityType,
                                                List<String> entityIds) throws AuthException {
        return assertExcludeEntities(authEntityType, entityIds, null);
    }

    @Override
    public ICurrentTenant assertExcludeEntity(AuthConstant.AuthEntityType authEntityType, String entityId, String errMsg) throws AuthException {
        return assertExcludeEntities(authEntityType, Arrays.asList(entityId), errMsg);
    }

    @Override
    public ICurrentTenant assertExcludeEntity(AuthConstant.AuthEntityType authEntityType, String entityId) throws AuthException {
        return assertExcludeEntity(authEntityType, entityId, null);
    }
}
